# ifndef POLYNOMIAL_H
# define POLYNOMIAL_H

# include<vector>
# include<iostream>
# include"Function.h"

/**
* @brief 定义一个多项式类，能够进行多项式的基本操作
* 
*/
class Polynomial : public Function
{
private:
    int deg;                    // 多项式次数
    std::vector<double> coff;   // 多项式的各项系数
    void clearTop();            // 用于抹去运算过程中最高次项为0的项
    
public:
    Polynomial();                                 // 初始化构造
    Polynomial(const std::vector<double> & vec);  // 赋值构造
    Polynomial(const Polynomial & poly);          // 深拷贝复制构造
    ~Polynomial(){};                              // 析构函数
    
    double operator() (const double & _x) const;  // 用于计算 x 对应函数值
    double operator[] (const int & n) const;      // 只读形式获取多项式第 n 项系数
    void operator= (Polynomial && poly);          // 重载左值引用赋值操作
    void operator= (Polynomial & poly);           // 重载右值引用赋值操作
    friend Polynomial operator+ (const Polynomial & p1, const Polynomial & p2);  // 实现普通多项式加法
    friend Polynomial operator+ (const Polynomial & poly, const double & a);     // 实现多项式和常数加法
    friend Polynomial operator- (const Polynomial & p1, const Polynomial & p2);  // 实现普通多项式减法
    friend Polynomial operator- (const Polynomial & poly, const double & a);     // 实现多项式和常数减法
    friend Polynomial operator* (const Polynomial & p1, const Polynomial & p2);  // 实现普通多项式乘法
    friend Polynomial operator* (const double & c, const Polynomial & poly);     // 实现多项式数乘

    double diff(const double & _x) const;          // 计算 x 处导数值
    Polynomial GetDiff() const;                    // 输出导函数
    int GetDeg() const;                            // 输出多项式次数
    void assign(const std::vector<double> & vec);  // 按照给定系数重构多项式
    void PrintCoff() const;                        // 从低次到高输出多项式系数
    void PrintPol() const;                         // 按照多项式形式输出多项式
};

/**
* @brief 初始化构造
* 
*/
Polynomial::Polynomial(): deg{0}, coff{0} {};


/**
* @brief 赋值构造
* 
*/
Polynomial::Polynomial(const std::vector<double> & vec) : 
coff{vec}
{
    deg = vec.size()-1;
    clearTop();
};

/**
* @brief 深拷贝复制构造
* 
*/
Polynomial::Polynomial(const Polynomial & poly) : 
coff{poly.coff}, deg{poly.deg} {};

/**
* @brief 用于抹去运算过程中最高次项为0的项
* 
*/
void Polynomial::clearTop()
{
    int n = deg;
    for (int i = n; i > 0; i--)
    {
        if (coff[i] == 0)
        {
            coff.pop_back();
            deg--;
        }
        else break;
    }
    return;
};

/**
* @brief 用于计算 x 对应函数值
* 
*/
double Polynomial::operator() (const double & _x) const
{
    double output = 0;
    for (int i = deg; i >= 0; i--)
    {
        output = coff[i] + output * _x;
    }
    return output;
};

/**
* @brief 只读形式获取多项式第 n 项系数
* 
*/
double Polynomial::operator[] (const int & n) const
{
    if (n < 0 || n > deg)
    {
        std::cout << "The index is out of range." << std::endl;
        return 0;
    }
    return coff[n];
};

/**
* @brief 重载左值引用赋值操作
* 
*/
void Polynomial::operator= (Polynomial && poly)
{
    std::vector<double> copy(poly.coff);
    coff.swap(copy);
    deg = coff.size() - 1;
};

/**
* @brief 重载右值引用赋值操作
* 
*/
void Polynomial::operator= (Polynomial & poly)
{
    coff.assign(poly.coff.begin(), poly.coff.end());
    deg = coff.size() - 1;
};

/**
* @brief 实现普通多项式加法
* 
*/
Polynomial operator+ (const Polynomial & p1, const Polynomial & p2)
{
    Polynomial output(p1);
    if (output.deg >= p2.deg)
    {
        for (int i = 0; i <= p2.deg; i++)
        {
            output.coff[i] += p2.coff[i];
        }
    }
    else
    {
        for (int i = 0; i <= output.deg; i++)
        {
            output.coff[i] += p2.coff[i];
        }
        for (int j = output.deg + 1; j <= p2.deg; j++)
        {
            output.coff.push_back(p2.coff[j]);
        }
        output.deg = p2.deg;
    }
    output.clearTop();
    return output;
};

/**
* @brief 实现多项式和常数加法
* 
*/
Polynomial operator+ (const Polynomial & poly, const double & a)
{
    Polynomial output(poly);
    output.coff[0] += a;
    return output;
};

/**
* @brief 实现普通多项式减法
* 
*/
Polynomial operator- (const Polynomial & p1, const Polynomial & p2)
{
    Polynomial output(p1);
    if (output.deg >= p2.deg)
    {
        for (int i = 0; i <= p2.deg; i++)
        {
            output.coff[i] -= p2.coff[i];
        }
    }
    else
    {
        for (int i = 0; i <= output.deg; i++)
        {
            output.coff[i] -= p2.coff[i];
        }
        for (int j = output.deg + 1; j <= p2.deg; j++)
        {
            output.coff.push_back(-1*p2.coff[j]);
        }
        output.deg = p2.deg;
    }
    output.clearTop();
    return output;
};

/**
* @brief 实现多项式和常数减法
* 
*/
Polynomial operator- (const Polynomial & poly, const double & a)
{
    Polynomial output(poly);
    output.coff[0] -= a;
    return output;
};

/**
* @brief 实现普通多项式乘法
* 
*/
Polynomial operator* (const Polynomial & p1, const Polynomial & p2)
{
    std::vector<double> cofficients;
    int n = p1.deg + p2.deg;
    for (int i = 0; i <= n; i++)
    {
        double part = 0;
        for (int j = 0; j <= i; j++)
        {
            if (j > p1.deg) break;
            if (i - j > p2.deg) continue;
            part += p1.coff[j] * p2.coff[i - j];
        }
        cofficients.push_back(part);
    }
    Polynomial output(cofficients);
    output.clearTop();
    return output;
};

/**
* @brief 实现多项式数乘
* 
*/
Polynomial operator* (const double & c, const Polynomial & poly)
{
    Polynomial output(poly);
    for (int i = 0; i <= output.deg; i++)
    {
        output.coff[i] *= c;
    }
    output.clearTop();
    return output;
};

/**
* @brief 计算 x 处导数值
* 
*/
double Polynomial::diff (const double & _x) const
{
    double output = 0;
    for (int i = deg; i >= 1; i--)
    {
        output = coff[i] * i + output * _x;
    }
    return output;
};

/**
* @brief 输出导函数
* 
*/
Polynomial Polynomial::GetDiff() const
{
    std::vector<double> vec;
    for (int i = 1; i <= deg; i++)
        vec.push_back(coff[i] * i);
    Polynomial out(vec);
    return out;
};

/**
* @brief 输出多项式次数
* 
*/
int Polynomial::GetDeg() const
{
    return deg;
};

/**
* @brief 按照给定系数重构多项式
* 
*/
void Polynomial::assign(const std::vector<double> & vec)
{
    coff.assign(vec.begin(), vec.end());
    deg = coff.size() - 1;
    return;
};

/**
* @brief 从低次到高输出多项式系数
* 
*/
void Polynomial::PrintCoff() const
{
    for (int i = 0; i <= deg; i++)
    {
        std::cout << coff[i] << " ";
    }
    std::cout << std::endl;
}

/**
* @brief 按照多项式形式输出多项式
* 
*/
void Polynomial::PrintPol() const
{
    if (deg == 0)
    {
        std::cout << coff[0] << std::endl;
    }
    else
    {
        std::cout << coff[deg] << "x^" << deg;
        for (int i = deg - 1; i > 0; i--)
        {
            if (coff[i] == 0) continue;
            if (coff[i] > 0)
                std::cout << "+" << coff[i] << "x^" << i;
            else
                std::cout << coff[i] << "x^" << i;
        }
        if (coff[0] > 0)
            std::cout << "+" << coff[0];
        else if (coff[0] < 0)
            std::cout << coff[0];
        std::cout << std::endl;
    }
}

# else
// Do nothing.
#endif